home *** CD-ROM | disk | FTP | other *** search
/ Apple WWDC 1996 / WWDC96_1996 (CD).toast / Technology Materials / MacApp Release 10 / MacApp Release 10 - HD Ready / Libraries / Framework / Sources / UMenuMgr.cp < prev    next >
Encoding:
Text File  |  1996-04-03  |  62.3 KB  |  2,157 lines  |  [TEXT/MPS ]

  1. //----------------------------------------------------------------------------------------
  2. // UMenuMgr.cp 
  3. // Copyright © 1984-96 by Apple Computer, Inc. All rights reserved.
  4. //----------------------------------------------------------------------------------------
  5.  
  6. //----------------------------------------------------------------------------------------
  7. // Theory of Operation
  8. //
  9. // This unit provides two features: It implements a command numbering system that is
  10. // independent of menu/ item placement, and implements a framework for optimizing menu
  11. // setups. The command numbering system works by assigning commands a unique command
  12. // number, and providing a mechanism for mapping command numbers to menu/ item pairs. A
  13. // set of routines are provide to manipulate commands via their command number rather
  14. // than their menu and item numbers.
  15. //
  16. // Each command can be assigned an integer command number from 1 to 32767. To associate a
  17. // command number with a menu item, menu resources are defined with the 'CMNU' resource
  18. // type--not the 'MENU' type. The 'CMNU' type is just like the 'MENU' type, with an
  19. // additional command number field for each menu item. This unit converts the 'CMNU'
  20. // resource into a 'MENU' dynamically at run time.
  21. //
  22. // The items of some menus cannot be determined until run-time. The font menu is an
  23. // example. In such cases, no command number is assigned by you. Instead, the command
  24. // number is equal to -(256 * menu + item). The procedure CommandToMenuItem converts a
  25. // command number to a menu id and item number by the following method:
  26. //
  27. // - If the command number is positive, the command table is searched for the number. If
  28. // it is found, CommandToMenuItem returns the corre- sponding menu id and item
  29. // number. Otherwise the menu and item are zero.
  30. //
  31. // - If the command number is negative, the menu number is the upper eight bits, and the
  32. // item number the lower eight bits, of the absolute value of the command number. (This
  33. // implies that menu id's must be <= 127 and item numbers must be <= 255.) The function
  34. // CommandFromMenuItem converts menu/ items to command numbers by the following method:
  35. //
  36. // - If the item number is positive, the command table is search for the given menu/ item
  37. // pair.  If found, the corresponding command number is returned. If not found, the number
  38. // returned is equal to
  39. //  -(256 * menu + item).
  40. //  - If the item number is negative, the number returned is equal to
  41. //  -item number.
  42. //
  43. // Note that CommandToMenuItem and CommandFromMenuItem work regardless of whether the
  44. // command is actually installed in the menu bar. MacApp takes advantage of this feature
  45. // by having a set of generic "buzz" commands, whose primary use is to set the name of the
  46. // Undo command (e.g. 'Undo Drawing').
  47. //
  48. // The second feature of this unit is to optimize menu setups (changing the appearance of
  49. // menus and items). Normally, each call to CheckItem, SetItemStyle and SetCommandIcon in
  50. // turn calls CalcMenuSize because the width or height of the menu may have changed. If
  51. // menu setups are done all at one time, then CalcMenuSize can be deferred until the end
  52. // of the setup process. The procedure PerformMenuSetup implements this mechanism. It relies
  53. // on the fact that menu setups are done all at once, and that you will call
  54. // SetCommandName, SetItemStyle and SetCommandIcon instead of SetItem, SetItemStyle and
  55. // SetCommandIcon. It works only for menus whose id is from 1 to mLastMenu. Menus with IDs
  56. // greater than mLastMenu are not affected by this scheme.
  57. //
  58. // PerformMenuSetup accepts one parameter, a procedure which actually implements the menu
  59. // appearance changes. SetupMenus performs the following steps:
  60. //
  61. // - Before calling your menu setup procedure, StartupMenuSetup is called. It disables all
  62. // menus and items, remembers the current menu proc and enabled flags of each menu, and
  63. // sets the MenuProc of each menu to gHNullMenuProc, thereby disabling CalcMenuSize.
  64. //
  65. // - Your procedure is called.It in turn calls SetCommandName, SetCmdStyle, SetCommandIcon,
  66. // Enable, EnableCheck, or a Toolbox routine (provided it isn't SetItem, SetItemStyle or
  67. // SetCommandIcon).
  68. //
  69. // - Menus with at least one enabled item are enabled, CalcMenuSize is called for those
  70. // menus that need it, each menu's menuproc is restored, and DrawMenuBar is called if the
  71. // enabled state of any menu changed.
  72. //----------------------------------------------------------------------------------------
  73.  
  74. #ifndef __UMENUMGR__
  75. #include "UMenuMgr.h"
  76. #endif
  77.  
  78. // MacApp
  79.  
  80. #ifndef __GEOMETRY__
  81. #include "Geometry.h"
  82. #endif
  83.  
  84. #if qContainer
  85. #ifndef __UCONTAINER__
  86. #include "UContainer.h"
  87. #endif
  88.  
  89. #endif
  90.  
  91. #ifndef __UCOREGLOBALS__
  92. #include "UCoreGlobals.h"
  93. #endif
  94.  
  95. #ifndef __UCOREUTILITIES__
  96. #include "UCoreUtilities.h"
  97. #endif
  98.  
  99. #ifndef __UDISPATCHER__
  100. #include "UDispatcher.h"
  101. #endif
  102.  
  103. #ifndef __UFAILURE__
  104. #include "UFailure.h"
  105. #endif
  106.  
  107. #ifndef __UITERATOR__
  108. #include "UIterator.h"
  109. #endif
  110.  
  111. #ifndef __ULIST__
  112. #include "UList.h"
  113. #endif
  114.  
  115. #ifndef __UMACAPPGLOBALS__
  116. #include "UMacAppGlobals.h"
  117. #endif
  118.  
  119. #ifndef __UMACAPPUTILITIES__
  120. #include "UMacAppUtilities.h"
  121. #endif
  122.  
  123. #ifndef __UMEMORY__
  124. #include "UMemory.h"
  125. #endif
  126.  
  127. #ifndef __UOBJECT__
  128. #include "UObject.h"
  129. #endif
  130.  
  131. #ifndef __UPATCH__
  132. #include "UPatch.h"
  133. #endif
  134.  
  135. #if qContainer
  136.  
  137. // CALib
  138.  
  139. #ifndef _CALIB_
  140. #include "CALib.h"
  141. #endif
  142.  
  143. // OpenDoc
  144.  
  145. #ifndef SOM_Module_OpenDoc_Commands_defined
  146. #include "CmdDefs.xh"
  147. #endif
  148.  
  149. #endif // qContainer
  150.  
  151. // Toolbox
  152.  
  153. #ifndef __BALLOONS__
  154. #include <Balloons.h>
  155. #endif
  156.  
  157. #ifndef __LOWMEM__
  158. #include <LowMem.h>
  159. #endif
  160.  
  161. #ifndef __MEMORY__
  162. #include <Memory.h>
  163. #endif
  164.  
  165. #ifndef __OSUTILS__
  166. #include <OSUtils.h>
  167. #endif
  168.  
  169. #ifndef __RESOURCES__
  170. #include <Resources.h>
  171. #endif
  172.  
  173. #ifndef __TEXTEDIT__
  174. #include <TextEdit.h>
  175. #endif
  176.  
  177. #ifndef __TOOLUTILS__
  178. #include <ToolUtils.h>
  179. #endif
  180.  
  181. #ifndef __TRAPS__
  182. #include <Traps.h>
  183. #endif
  184.  
  185. // ANSI
  186.  
  187. #ifndef __STDIO__
  188. #include <stdio.h>
  189. #endif
  190.  
  191. //----------------------------------------------------------------------------------------
  192. const Boolean kHierarchical = TRUE;
  193. const Boolean kNotHierarchical = !kHierarchical;
  194.  
  195. const Boolean kDoHierarchical = TRUE;
  196. const Boolean kDontDoHierarchical = !kDoHierarchical;
  197.  
  198. struct MenuCmdRecord
  199. {
  200.     CommandNumber theCmdNumber;
  201.     ResNumber theMenuNumber;
  202.     short theItemNumber;
  203. };
  204.  
  205. typedef MenuCmdRecord *MenuCmdRecordPtr, ** MenuCmdRecordHandle;
  206.  
  207. //========================================================================================
  208. // GLOBAL Procedures
  209. //========================================================================================
  210. static CompareResult TestMenuResIDs(ArrayIndex anItem,
  211.                                     void* yourDataPtr);
  212. static CompareResult CmdToMenuItem_TestItem(ArrayIndex anItem,
  213.                                             void* yourDataPtr);
  214. static CompareResult TestForMenuID(Handle anItem,
  215.                                    void* yourDataPtr);
  216. static char TraceMenuName(CommandNumber aCommand);
  217. static Boolean IsSetupMenu(MenuRef aMenuRef,
  218.                            Boolean isHierarchical);
  219.  
  220. //----------------------------------------------------------------------------------------
  221. // TCmdTable:
  222. //----------------------------------------------------------------------------------------
  223.  
  224. class TCmdTable : public TSortedDynamicArray
  225. {
  226.     MA_DECLARE_CLASS;
  227.  
  228. public:
  229.     virtual ~TCmdTable();
  230.  
  231.     inline void ICmdTable()
  232.     { ISortedDynamicArray(0, sizeof(MenuCmdRecord)); }
  233.  
  234.     virtual CompareResult CompareElements(void* Element1,
  235.                                           void* Element2);// override 
  236.  
  237.     virtual void CommandToMenuItem(CommandNumber theCommand,
  238.                                    MenuID& menu,
  239.                                    short& item);
  240.     virtual CommandNumber CommandFromMenuItem(short menu,
  241.                                               short item);
  242.     // Given a menuID,item # return the appropriate command number. 
  243.     // If there is no such command number, return -BOR(((menu) << 8), item). 
  244.     // If the item number is <0 then assume that it is a negative command number.
  245.  
  246.     void AddToTable(CommandNumber commandNumber,
  247.                     MenuID menuNumber,
  248.                     short itemNumber);
  249.  
  250.     void AddNewCmdToTableAndUpdateTable(CommandNumber commandNumber,
  251.                                         MenuID menuNumber,
  252.                                         short itemNumber);
  253.     // This adds a menu item/command number after the menus have already been 
  254.     // set up, and updates all the tables
  255.  
  256.     void DeleteCmdAndUpdateTable(CommandNumber theMenuItemCommandNumber);
  257.     // This deletes a menu item/command number after the menus have already
  258.     // been set up, and updates all the tables
  259. };
  260.  
  261.  
  262. //----------------------------------------------------------------------------------------
  263. // TMenuTable:
  264. //----------------------------------------------------------------------------------------
  265.  
  266. class TMenuTable : public TSortedHandleList
  267. {
  268.     MA_DECLARE_CLASS;
  269.  
  270. public:
  271.     virtual ~TMenuTable();
  272.  
  273.     inline void IMenuTable()
  274.     { ISortedHandleList(); }
  275.  
  276.     MenuRef GetMenu(MenuID menuID);
  277.  
  278.     virtual CompareResult Compare(Handle item1,
  279.                                   Handle item2);// override 
  280. };
  281.  
  282.  
  283. typedef struct MenuIDRecord
  284. {
  285.     ResNumber fMenuResID;
  286.     MenuID fMenuID;
  287. }    *MenuIDRecordPtr, ** MenuIDRecordHandle;
  288.  
  289.  
  290. //----------------------------------------------------------------------------------------
  291. // TMenuIDList:
  292. //----------------------------------------------------------------------------------------
  293.  
  294. class TMenuIDList : public TSortedDynamicArray
  295. {
  296.     MA_DECLARE_CLASS;
  297.  
  298. public:
  299.     virtual ~TMenuIDList();
  300.  
  301.     inline void IMenuIDList()
  302.     { ISortedDynamicArray(0, sizeof(MenuIDRecord)); }
  303.  
  304.     virtual CompareResult CompareElements(void* Element1,
  305.                                           void* Element2);// override 
  306.  
  307.     MenuID MenuIDFromResID(ResNumber menuResID);
  308.  
  309.     void AddToTable(ResNumber menuResID,
  310.                     MenuID menuID);
  311. };
  312.  
  313.  
  314. static Handle pHNullMenuProc;                    // Handle to NULL menu proc 
  315.  
  316. TCmdTable* gCmdTable;                            // command numbers and their associated menu
  317. // and item numbers
  318.  
  319. TMenuTable* gMenuTable;                            // list of menus created/managed by MacApp 
  320.  
  321. TMenuIDList* gMenuIDList;                        // list of menu IDs sorted by resource ID
  322.  
  323. pascal void NullMenuProc(short message,
  324.                          MenuRef aMenuRef,
  325.                          CRect& menuRect,
  326.                          CPoint hitPt,
  327.                          short& whichItem);
  328.  
  329. //----------------------------------------------------------------------------------------
  330.  
  331. static Boolean gMenusAreInvalid = TRUE;
  332. // Used by InvalidateMenus to track whether menus need to be setup.
  333.  
  334. TMenuBarManager* gMenuBarManager;
  335.  
  336. #if qDebug
  337. Boolean gTraceSetupMenus;
  338. #endif
  339.  
  340.  
  341. //========================================================================================
  342. // struct CGetMenuID
  343. //========================================================================================
  344.  
  345. struct CGetMenuID
  346. {
  347. public:
  348.     // Fields
  349.     ResNumber& menuResID;
  350.     TMenuIDList* theMenuIDList;
  351.  
  352.     // Constructor
  353.     inline CGetMenuID(ResNumber& aMenuResID,
  354.                TMenuIDList* aMenuIDList) :
  355.         menuResID(aMenuResID),
  356.         theMenuIDList(aMenuIDList)
  357.     { }
  358. };
  359.  
  360.  
  361. //----------------------------------------------------------------------------------------
  362. // TestMenuResIDs: 
  363. //----------------------------------------------------------------------------------------
  364. #pragma segment MAMenuRes
  365.  
  366. CompareResult TestMenuResIDs(ArrayIndex anItem,
  367.                              void* yourDataPtr)
  368. {
  369.     CompareResult returnVal = kItemEqualCriteria;
  370.  
  371.     CGetMenuID * testInfo = (CGetMenuID *)yourDataPtr;
  372.     ResNumber theMenuResIDitem = ((MenuIDRecordPtr)testInfo->theMenuIDList->ComputeAddress(anItem))->fMenuResID;
  373.  
  374.     if (theMenuResIDitem > testInfo->menuResID)
  375.         returnVal = kItemGreaterThanCriteria;
  376.     else if (theMenuResIDitem < testInfo->menuResID)
  377.         returnVal = kItemLessThanCriteria;
  378.  
  379.     return returnVal;
  380. }
  381.  
  382.  
  383. //========================================================================================
  384. // CLASS TMenuIDList
  385. //========================================================================================
  386. #undef Inherited
  387. #define Inherited TSortedDynamicArray
  388.  
  389. #pragma segment MAInit
  390. MA_DEFINE_CLASS_M1(TMenuIDList,
  391.                    Inherited);
  392.  
  393. //----------------------------------------------------------------------------------------
  394. // TMenuIDList destructor
  395. //----------------------------------------------------------------------------------------
  396. #pragma segment MADestructorRes
  397.  
  398. TMenuIDList::~TMenuIDList()
  399. {
  400. }
  401.  
  402. //----------------------------------------------------------------------------------------
  403. // TMenuIDList::CompareElements: 
  404. //----------------------------------------------------------------------------------------
  405. #pragma segment MAMenuRes
  406.  
  407. CompareResult TMenuIDList::CompareElements(void* Element1,
  408.                                            void* Element2)// override 
  409. {
  410.     CompareResult returnVal = kItem1EqualItem2;
  411.  
  412.     ResNumber theResNumber1 = ((MenuIDRecordPtr)Element1)->fMenuResID;
  413.     ResNumber theResNumber2 = ((MenuIDRecordPtr)Element2)->fMenuResID;
  414.  
  415.     if (theResNumber1 > theResNumber2)
  416.         returnVal = kItem1GreaterThanItem2;
  417.     else if (theResNumber1 < theResNumber2)
  418.         returnVal = kItem1LessThanItem2;
  419.  
  420.     return returnVal;
  421. }
  422.  
  423. //----------------------------------------------------------------------------------------
  424. // TMenuIDList::AddToTable: 
  425. //----------------------------------------------------------------------------------------
  426. #pragma segment MAMenuRes
  427.  
  428. void TMenuIDList::AddToTable(ResNumber menuResID,
  429.                              MenuID menuID)
  430. {
  431.     MenuIDRecord arec;
  432.  
  433.     arec.fMenuResID = menuResID;
  434.     arec.fMenuID = menuID;
  435.  
  436.     InsertElementInOrder((Ptr) & arec);
  437. }
  438.  
  439. //----------------------------------------------------------------------------------------
  440. // TMenuIDList::MenuIDFromResID: 
  441. //----------------------------------------------------------------------------------------
  442. #pragma segment MAMenuRes
  443.  
  444. MenuID TMenuIDList::MenuIDFromResID(ResNumber menuResID)
  445. {
  446.     ArrayIndex index;
  447.     CGetMenuID aCGetMenuID(menuResID, this);
  448.  
  449.     if (DoSearchElement(&TestMenuResIDs, &aCGetMenuID, index))
  450.     {
  451.         MenuIDRecordPtr aMenuIDListPtr = (MenuIDRecordPtr)ComputeAddress(index);
  452.         return aMenuIDListPtr->fMenuID;
  453.     }
  454.  
  455.     return 0;
  456. }
  457.  
  458.  
  459. //========================================================================================
  460. // CLASS TCmdTable
  461. //========================================================================================
  462. #undef Inherited
  463. #define Inherited TSortedDynamicArray
  464.  
  465. #pragma segment MAInit
  466. MA_DEFINE_CLASS_M1(TCmdTable,
  467.                    Inherited);
  468.  
  469. //----------------------------------------------------------------------------------------
  470. // TCmdTable destructor
  471. //----------------------------------------------------------------------------------------
  472. #pragma segment MADestructorRes
  473.  
  474. TCmdTable::~TCmdTable()
  475. {
  476. }
  477.  
  478. //----------------------------------------------------------------------------------------
  479. // TCmdTable::CompareElements: 
  480. //----------------------------------------------------------------------------------------
  481. #pragma segment MAMenuRes
  482.  
  483. CompareResult TCmdTable::CompareElements(void* Element1,
  484.                                          void* Element2)// override 
  485. {
  486.     CompareResult returnVal = kItem1EqualItem2;
  487.  
  488.     CommandNumber theCommanditem1 = ((MenuCmdRecordPtr)Element1)->theCmdNumber;
  489.     CommandNumber theCommanditem2 = ((MenuCmdRecordPtr)Element2)->theCmdNumber;
  490.  
  491.     if (theCommanditem1 > theCommanditem2)
  492.         returnVal = kItem1GreaterThanItem2;
  493.     else if (theCommanditem1 < theCommanditem2)
  494.         returnVal = kItem1LessThanItem2;
  495.  
  496.     return returnVal;
  497. }
  498.  
  499. //--------------------------------------------------------------------------------------------------
  500.  
  501. class CCmdToMenuItem
  502. {
  503. public:
  504.     CommandNumber& theCommand;
  505.     TCmdTable* theCmdTable;
  506.  
  507.     inline CCmdToMenuItem(CommandNumber& aCommand,
  508.                    TCmdTable* aCmdTable) :
  509.         theCommand(aCommand),
  510.         theCmdTable(aCmdTable)
  511.     { }
  512. };
  513.  
  514. #pragma segment MAMenuRes
  515. CompareResult CmdToMenuItem_TestItem(ArrayIndex anItem,
  516.                                      void* yourDataPtr)
  517. {
  518.     CompareResult returnVal = kItemEqualCriteria;
  519.  
  520.     CCmdToMenuItem * testInfo = (CCmdToMenuItem *)yourDataPtr;
  521.     CommandNumber theCommanditem;
  522.  
  523.     theCommanditem = ((MenuCmdRecordPtr)testInfo->theCmdTable->ComputeAddress(anItem))->theCmdNumber;
  524.  
  525.     if (theCommanditem > testInfo->theCommand)
  526.         returnVal = kItemGreaterThanCriteria;
  527.     else if (theCommanditem < testInfo->theCommand)
  528.         returnVal = kItemLessThanCriteria;
  529.  
  530.     return returnVal;
  531. }
  532.  
  533. //----------------------------------------------------------------------------------------
  534. // TCmdTable::CommandToMenuItem: 
  535. //----------------------------------------------------------------------------------------
  536. #pragma segment MAMenuRes
  537.  
  538. void TCmdTable::CommandToMenuItem(CommandNumber theCommand,
  539.                                   MenuID& menu,
  540.                                   short& item)
  541. {
  542.     ArrayIndex index = 0;
  543.     MenuCmdRecordPtr aMenuCmdRecordPtr;
  544.     CCmdToMenuItem aCCmdToMenuItem(theCommand, this);
  545.  
  546.     if (theCommand < 0)                            /* negative commands are mapped not table based */
  547.     {
  548.         menu = (short)((-theCommand) >> 8);
  549.         item = (short)((-theCommand) & 255);
  550.     }
  551.     else
  552.     {
  553.         if (DoSearchElement(&CmdToMenuItem_TestItem, &aCCmdToMenuItem, index))
  554.         {
  555.             do
  556.             {
  557.                 index--;
  558.                 if (index == 0)
  559.                     break;
  560.                 aMenuCmdRecordPtr = (MenuCmdRecordPtr)ComputeAddress(index);
  561.             } while (aMenuCmdRecordPtr->theCmdNumber == theCommand);
  562.  
  563.             ++index;
  564.  
  565.             do
  566.             {
  567.                 aMenuCmdRecordPtr = (MenuCmdRecordPtr)ComputeAddress(index);
  568.                 if (aMenuCmdRecordPtr->theCmdNumber == theCommand)
  569.                 {
  570.                     menu = aMenuCmdRecordPtr->theMenuNumber;
  571.                     item = aMenuCmdRecordPtr->theItemNumber;
  572.                     if (::GetMenuHandle(menu) != NULL)
  573.                         break;
  574.                 }
  575.                 ++index;
  576.             } while (aMenuCmdRecordPtr->theCmdNumber == theCommand);
  577.         }
  578.         else                                    // not found
  579.             {
  580.                 menu = 0;
  581.                 item = 0;
  582.             }
  583.     }
  584. }
  585.  
  586. //----------------------------------------------------------------------------------------
  587. // TCmdTable::CommandFromMenuItem: 
  588. //----------------------------------------------------------------------------------------
  589. #pragma segment MAMenuRes
  590.  
  591. CommandNumber TCmdTable::CommandFromMenuItem(short menu,
  592.                                              short item)
  593.  
  594. // Given a menuID/item # return the appropriate command number. if there
  595. // is no such command number, return -BOR(((menu) << 8), item).  If the
  596. // item number is <0 then assume that it is a negative command number.
  597. {
  598.     if (item < 0)
  599.         return -item;
  600.     else
  601.     {
  602.         if (item > 0)
  603.         {
  604.             // Search the table linearly. 
  605.             for (ArrayIndex i = 1; i <= GetSize(); ++i)
  606.             {
  607.                 MenuCmdRecordPtr aMenuCmdRecordPtr = (MenuCmdRecordPtr)ComputeAddress(i);
  608.                 if ((menu == aMenuCmdRecordPtr->theMenuNumber) && (item == aMenuCmdRecordPtr->theItemNumber))
  609.                 {
  610.                     return aMenuCmdRecordPtr->theCmdNumber;
  611.                 }
  612.             }
  613.         }
  614.  
  615. #if qDebugMsg
  616.         if ((menu > 127) || (item > 255))
  617.         {
  618.             fprintf(stderr, "menu : %1d , item : %1d \n", menu, item);
  619.             fprintf(stderr, "Menu/item number is too big for a negative command number!\n");
  620.             ProgramBreak("Try using a negative item number instead.");
  621.         }
  622. #endif
  623.  
  624.         return -((menu << 8) | item);
  625.     }
  626. }
  627.  
  628. //----------------------------------------------------------------------------------------
  629. // TCmdTable::AddToTable: 
  630. //----------------------------------------------------------------------------------------
  631. #pragma segment MAInit
  632.  
  633. void TCmdTable::AddToTable(CommandNumber commandNumber,
  634.                            MenuID menuNumber,
  635.                            short itemNumber)
  636. {
  637.     MenuCmdRecord arec;
  638.  
  639.     if (commandNumber > 0)                        // Negative numbers are mapped not tabled 
  640.     {
  641.         arec.theCmdNumber = commandNumber;
  642.         arec.theMenuNumber = menuNumber;
  643.         arec.theItemNumber = itemNumber;
  644.  
  645.         InsertElementInOrder((Ptr) & arec);
  646.     }
  647. }
  648.  
  649.  
  650. //----------------------------------------------------------------------------------------
  651. // TCmdTable::AddNewCmdToTableAndUpdateTable:
  652. //----------------------------------------------------------------------------------------
  653. #pragma segment MAMenuRes
  654.  
  655. void TCmdTable::AddNewCmdToTableAndUpdateTable(CommandNumber commandNumber,
  656.                                                MenuID menuNumber,
  657.                                                short itemNumber)
  658. {
  659.     MenuCmdRecord arec;
  660.  
  661.     for (ArrayIndex i = 1; i <= GetSize(); i++)
  662.     {
  663.         GetElementsAt(i, &arec, 1);
  664.  
  665.         if ((arec.theMenuNumber == menuNumber) && (arec.theItemNumber >= itemNumber))
  666.         {
  667.             // If we have found an item in the same menu as we are adding to and it is
  668.             // the same index or greater then bump its itemNumber
  669.             arec.theItemNumber++;
  670.  
  671.             // Write it back out
  672.             ReplaceElementsAt(i, &arec, 1);
  673.         }
  674.     }
  675.  
  676.     // Insert the new menu item
  677.     arec.theCmdNumber = commandNumber;
  678.     arec.theMenuNumber = menuNumber;
  679.     arec.theItemNumber = itemNumber;
  680.  
  681.     InsertElementInOrder((Ptr) & arec);
  682. }
  683.  
  684. //----------------------------------------------------------------------------------------
  685. // TCmdTable::DeleteCmdAndUpdateTable:
  686. //----------------------------------------------------------------------------------------
  687. #pragma segment MAMenuRes
  688.  
  689. void TCmdTable::DeleteCmdAndUpdateTable(CommandNumber theMenuItemCommandNumber)
  690. {
  691.     MenuCmdRecord arec;
  692.     short menuNumber;
  693.     short itemNumber;
  694.  
  695.     CommandToMenuItem(theMenuItemCommandNumber, menuNumber, itemNumber);
  696.  
  697.     for (ArrayIndex i = 1; i <= GetSize(); i++)
  698.     {
  699.         GetElementsAt(i, &arec, 1);
  700.  
  701.         if (arec.theMenuNumber == menuNumber)
  702.         {
  703.             if (arec.theItemNumber == itemNumber)
  704.             {
  705.                 // Delete the element
  706.                 DeleteElementsAt(i, 1);
  707.  
  708.                 // Back up one element
  709.                 --i;
  710.             }
  711.             else if (arec.theItemNumber > itemNumber)
  712.             {
  713.                 // If we have found an item in the same menu as we are deleting from and its
  714.                 // index is greater then decrement its itemNumber
  715.                 arec.theItemNumber--;
  716.  
  717.                 // Write it back out
  718.                 ReplaceElementsAt(i, &arec, 1);
  719.             }
  720.         }
  721.     }
  722. }
  723.  
  724. //----------------------------------------------------------------------------------------
  725. // TestForMenuID: 
  726. //----------------------------------------------------------------------------------------
  727. #pragma segment MAMenuRes
  728. CompareResult TestForMenuID(Handle anItem,
  729.                             void* yourDataPtr)
  730. {
  731.     CompareResult returnVal = kItemEqualCriteria;
  732.  
  733.     MenuID * menuID = (MenuID *)yourDataPtr;
  734.  
  735.     short menuIDitem = (*((MenuRef)anItem))->menuID;
  736.  
  737.     if (menuIDitem > *menuID)
  738.         returnVal = kItemGreaterThanCriteria;
  739.     else if (menuIDitem < *menuID)
  740.         returnVal = kItemLessThanCriteria;
  741.  
  742.     return returnVal;
  743. }
  744.  
  745.  
  746. //========================================================================================
  747. // CLASS TMenuTable
  748. //========================================================================================
  749. #undef Inherited
  750. #define Inherited TSortedHandleList
  751.  
  752. #pragma segment MAInit
  753. MA_DEFINE_CLASS_M1(TMenuTable,
  754.                    Inherited);
  755.  
  756. //----------------------------------------------------------------------------------------
  757. // TMenuTable destructor
  758. //----------------------------------------------------------------------------------------
  759. #pragma segment MADestructorRes
  760.  
  761. TMenuTable::~TMenuTable()
  762. {
  763. }
  764.  
  765. //----------------------------------------------------------------------------------------
  766. // TMenuTable::GetMenu: 
  767. //----------------------------------------------------------------------------------------
  768. #pragma segment MAMenuRes
  769.  
  770. MenuRef TMenuTable::GetMenu(MenuID menuID)
  771. {
  772.     ArrayIndex index;
  773.  
  774.     return ((MenuRef)DoSearch(&TestForMenuID, &menuID, index));// discard index 
  775. }
  776.  
  777. //----------------------------------------------------------------------------------------
  778. // TMenuTable::Compare: 
  779. //----------------------------------------------------------------------------------------
  780. #pragma segment MAMenuRes
  781.  
  782. CompareResult TMenuTable::Compare(Handle item1,
  783.                                   Handle item2)    // override 
  784. {
  785.     CompareResult returnVal = kItem1EqualItem2;
  786.  
  787.     MenuID menuID1 = (*((MenuRef)item1))->menuID;
  788.     MenuID menuID2 = (*((MenuRef)item2))->menuID;
  789.  
  790.     if (menuID1 > menuID2)
  791.         returnVal = kItem1GreaterThanItem2;
  792.     else if (menuID1 < menuID2)
  793.         returnVal = kItem1LessThanItem2;
  794.  
  795.     return returnVal;
  796. }
  797.  
  798.  
  799. //========================================================================================
  800. // GLOBAL Procedures
  801. //========================================================================================
  802. #undef Inherited
  803.  
  804. #if qDebugMsg
  805.  
  806. //----------------------------------------------------------------------------------------
  807. // TraceMenuName: 
  808. //----------------------------------------------------------------------------------------
  809. #pragma segment MADebug
  810.  
  811. char TraceMenuName(CommandNumber aCommand)
  812. // For debugging purposes only--used to dump the name and number of a command 
  813. {
  814.     CStr255 cmdName;
  815.  
  816.     CommandToName(aCommand, cmdName);
  817.     fprintf(stderr, " %1d [%s],", aCommand, (const char*)cmdName);
  818.     return ' ';
  819. }
  820.  
  821. #endif
  822.  
  823. //----------------------------------------------------------------------------------------
  824. // InvalidateMenus: 
  825. //----------------------------------------------------------------------------------------
  826. #pragma segment MAMenuRes
  827.  
  828. void InvalidateMenus()
  829. {
  830.     gMenusAreInvalid = TRUE;
  831. }
  832.  
  833. //----------------------------------------------------------------------------------------
  834. #pragma segment MAMenuRes
  835.  
  836. #if PRAGMA_ALIGN_SUPPORTED
  837. #pragma options align=mac68k
  838. #endif
  839.  
  840. struct MenuBarRecord
  841. {
  842.     ResNumber nMenus;
  843.     ResNumber menuResID[1000];
  844. };
  845.  
  846. #if PRAGMA_ALIGN_SUPPORTED
  847. #pragma options align=reset
  848. #endif
  849.  
  850. //----------------------------------------------------------------------------------------
  851. // AddMenuBar: 
  852. //----------------------------------------------------------------------------------------
  853. typedef MenuBarRecord* MenuBarPtr, ** MenuBarHandle;
  854.  
  855. void AddMenuBar(ResNumber itsID,
  856.                 Boolean isHierarchical)
  857. {
  858.     short hier = 0;
  859.     MenuBarHandle hmbar;
  860.  
  861.     if (isHierarchical)
  862.         hier = -1;
  863.  
  864.     hmbar = (MenuBarHandle)GetResource('MBAR', itsID);
  865.     if (hmbar)
  866.     {
  867.         for (ResNumber i = 0; i < (*hmbar)->nMenus; ++i)
  868.         {
  869.             ResNumber menuResID = (*hmbar)->menuResID[i];
  870.             MenuID menuID = gMenuIDList->MenuIDFromResID(menuResID);
  871.             if (!::GetMenuHandle(menuID))        // do nothing if it's already in menubar
  872.             {
  873.                 MenuRef aMenu = MAGetMenu(menuResID);
  874.                 if (aMenu)
  875.                 {
  876.                     MAInsertMenu(aMenu, menuResID, hier);
  877.  
  878.                     // a visible menu needed insertion thus the menubar became invalid
  879.                     if (!isHierarchical)
  880.                         InvalidateMenuBar();
  881.                 }
  882.             }
  883.         }
  884.  
  885.         ReleaseResource((Handle)hmbar);
  886.         // hmbar = NULL;
  887.     }
  888. }
  889.  
  890. //----------------------------------------------------------------------------------------
  891. // GetIndMenu: 
  892. //----------------------------------------------------------------------------------------
  893.  
  894. MenuRef GetIndMenu(ResNumber itsID,
  895.                    ResNumber itsIndex)
  896. {
  897.     MenuRef theMenu = NULL;
  898.  
  899.     MenuBarHandle hmbar = (MenuBarHandle)GetResource('MBAR', itsID);
  900.     if (hmbar)
  901.     {
  902.         ResNumber menuResID = (*hmbar)->menuResID[itsIndex - 1];
  903.         MenuID menuID = gMenuIDList->MenuIDFromResID(menuResID);
  904.         theMenu = MAGetMenu(menuResID);
  905.         ReleaseResource((Handle)hmbar);
  906.     }
  907.     return theMenu;
  908. }
  909.  
  910. //----------------------------------------------------------------------------------------
  911. // CountMenus: 
  912. //----------------------------------------------------------------------------------------
  913.  
  914. short CountMenus(ResNumber itsID)
  915. {
  916.     short numMenus = 0;
  917.  
  918.     MenuBarHandle hmbar = (MenuBarHandle)GetResource('MBAR', itsID);
  919.     if (hmbar)
  920.     {
  921.         numMenus = (*hmbar)->nMenus;
  922.         ReleaseResource((Handle)hmbar);
  923.     }
  924.     return numMenus;
  925. }
  926.  
  927. //----------------------------------------------------------------------------------------
  928. // ValidateMenus: 
  929. //----------------------------------------------------------------------------------------
  930. #pragma segment MAMenuRes
  931.  
  932. void ValidateMenus()
  933. {
  934.     gMenusAreInvalid = FALSE;
  935. }
  936.  
  937. //----------------------------------------------------------------------------------------
  938. // MenusHavePendingUpdate: 
  939. //----------------------------------------------------------------------------------------
  940. #pragma segment MAMenuRes
  941.  
  942. Boolean MenusHavePendingUpdate()
  943. {
  944.     return gMenusAreInvalid;
  945. }
  946.  
  947. //----------------------------------------------------------------------------------------
  948. // InvalidateMenuBar: 
  949. //----------------------------------------------------------------------------------------
  950. #pragma segment MAMenuRes
  951.  
  952. void InvalidateMenuBar()
  953. {
  954.     InvalidateMenus();                            // if the menubar is invalidated then the
  955.     // menu items must be also
  956.  
  957.     // Systems have "InvalMenuBar"... use that functionality. The system will redraw
  958.     // the menu bar at the next convenient time.
  959.  
  960.     InvalMenuBar();
  961. }
  962.  
  963. //----------------------------------------------------------------------------------------
  964. // CommandEnabled: 
  965. //----------------------------------------------------------------------------------------
  966. #pragma segment MAMenuRes
  967.  
  968. Boolean CommandEnabled(CommandNumber command)
  969. {
  970.     Boolean returnVal = FALSE;
  971.  
  972.     MenuID menuNo;
  973.     short itemNo;
  974.     MenuRef theMenu;
  975.  
  976.     theMenu = CommandToComponents(command, menuNo, itemNo);
  977.  
  978.     if (theMenu)
  979.         if ((itemNo > 0) && (itemNo < 32))
  980.             returnVal = ((((*theMenu)->enableFlags >> itemNo) & 0x01) != 0);
  981.         else
  982.             returnVal = TRUE;
  983.  
  984.     return returnVal;
  985. }
  986.  
  987. //----------------------------------------------------------------------------------------
  988. // CommandFromMenuItem: 
  989. //----------------------------------------------------------------------------------------
  990. #pragma segment MAMenuRes
  991.  
  992. CommandNumber CommandFromMenuItem(short menu,
  993.                                   short item)
  994. {
  995.     return gCmdTable->CommandFromMenuItem(menu, item);
  996. }
  997.  
  998. //----------------------------------------------------------------------------------------
  999. // CommandToMenuItem: 
  1000. //----------------------------------------------------------------------------------------
  1001. #pragma segment MAMenuRes
  1002.  
  1003. void CommandToMenuItem(CommandNumber aCommand,
  1004.                        MenuID& menu,
  1005.                        short& item)
  1006. {
  1007.     gCmdTable->CommandToMenuItem(aCommand, menu, item);
  1008. }
  1009.  
  1010. //----------------------------------------------------------------------------------------
  1011. // CommandToName: 
  1012. //----------------------------------------------------------------------------------------
  1013. #pragma segment MAMenuRes
  1014.  
  1015. void CommandToName(CommandNumber aCommand,
  1016.                    CStr255& menuText)
  1017. {
  1018.     menuText.Empty();
  1019.  
  1020.     short anItem;
  1021.     ResNumber aMenu;
  1022.     MenuRef mHandle = CommandToComponents(aCommand, aMenu, anItem);
  1023.     if (mHandle)
  1024.         GetMenuItemText(mHandle, anItem, menuText);
  1025. }
  1026.  
  1027. //----------------------------------------------------------------------------------------
  1028. // CommandToComponents: 
  1029. //----------------------------------------------------------------------------------------
  1030. #pragma segment MAMenuRes
  1031.  
  1032. MenuRef CommandToComponents(CommandNumber command,
  1033.                             MenuID& menuNo,
  1034.                             short& itemNo)
  1035. {
  1036.     MenuRef returnVal = NULL;
  1037.  
  1038.     CommandToMenuItem(command, menuNo, itemNo);
  1039.     if (menuNo)                                    // was found 
  1040.         returnVal = MAGetMenuRef(menuNo);
  1041.  
  1042.     return returnVal;
  1043. }
  1044.  
  1045. //----------------------------------------------------------------------------------------
  1046. // Enable: 
  1047. //----------------------------------------------------------------------------------------
  1048. #pragma segment MAMenuRes
  1049.  
  1050. void Enable(CommandNumber aCommand,
  1051.             Boolean canDo)
  1052. {
  1053. #if qDebugMsg
  1054.     if (gTraceSetupMenus)
  1055.         fprintf(stderr, "..... Enable(%c%s)\n", TraceMenuName(aCommand), (const char*)gBoolString[canDo]);
  1056. #endif
  1057.  
  1058.     MenuID menu;
  1059.     short item;
  1060.  
  1061.     MenuRef aMenuRef = CommandToComponents(aCommand, menu, item);
  1062.     if (aMenuRef)
  1063.         if (canDo)
  1064.             EnableItem(aMenuRef, item);
  1065.         else
  1066.             DisableItem(aMenuRef, item);
  1067. }
  1068.  
  1069. //----------------------------------------------------------------------------------------
  1070. // EnableCheck: 
  1071. //----------------------------------------------------------------------------------------
  1072. #pragma segment MAMenuRes
  1073.  
  1074. void EnableCheck(CommandNumber aCommand,
  1075.                  Boolean canDo,
  1076.                  Boolean checkIt)
  1077. {
  1078. #if qDebugMsg
  1079.     if (gTraceSetupMenus)
  1080.         fprintf(stderr, "..... EnableCheck(%c%s, %s)\n", TraceMenuName(aCommand), (const char*)gBoolString[canDo], (const char*)gBoolString[checkIt]);
  1081. #endif
  1082.  
  1083.     MenuID menu;
  1084.     short item;
  1085.  
  1086.     MenuRef aMenuRef = CommandToComponents(aCommand, menu, item);
  1087.     if (aMenuRef)
  1088.     {
  1089.         if (canDo)
  1090.             EnableItem(aMenuRef, item);
  1091.         else
  1092.             DisableItem(aMenuRef, item);
  1093.         CheckItem(aMenuRef, item, checkIt);
  1094.     }
  1095. }
  1096.  
  1097. //========================================================================================
  1098. // GLOBAL Procedures
  1099. //========================================================================================
  1100. #undef Inherited
  1101.  
  1102. //----------------------------------------------------------------------------------------
  1103. // GetResMenu: Allow us to get a menu when it's not available via ::GetMenuHandle.
  1104. //----------------------------------------------------------------------------------------
  1105. MenuRef GetResMenu(ResNumber menuResID)
  1106. {
  1107.     MenuRef theMenuRef = NULL;
  1108.     FailInfo fi;
  1109.  
  1110.     short oldResFile = MACurResFile();
  1111.  
  1112.     Try(fi)
  1113.     {
  1114.         MAUseResFile(gApplicationRefNum);
  1115.         theMenuRef = (MenuRef)GetResource('MENU', menuResID);
  1116.         fi.Success();
  1117.     }
  1118.     else
  1119.     {
  1120.         MAUseResFile(oldResFile);
  1121.         fi.ReSignal();
  1122.     }
  1123.     MAUseResFile(oldResFile);
  1124.  
  1125.     return theMenuRef;
  1126. }
  1127.  
  1128. //----------------------------------------------------------------------------------------
  1129. // ConvertToMenu: 
  1130. //----------------------------------------------------------------------------------------
  1131. #pragma segment MAInit
  1132.  
  1133. MenuRef ConvertToMenu(Handle CMNUHandle)
  1134. {
  1135.     MenuRef theMenuRef = NULL;
  1136.     Ptr theCMNUPtr;
  1137.     Ptr theMENUPtr;
  1138.     short i;
  1139.     MenuID menuNo;
  1140.     short itemNo;
  1141.     CommandNumber cmdNo;
  1142.     Ptr endPtr;
  1143.  
  1144.     theMenuRef = (MenuRef)NewPermHandle(GetHandleSize(CMNUHandle));
  1145.     LockHandle(CMNUHandle);
  1146.     LockHandle((Handle)theMenuRef);
  1147.  
  1148.     theCMNUPtr = (Ptr)StripLong(*CMNUHandle);
  1149.     theMENUPtr = (Ptr)StripLong(*theMenuRef);
  1150.     menuNo = *((IntegerPtr)theCMNUPtr);
  1151.  
  1152.     i = (*((CStr255 *)(theCMNUPtr + 14))).Length() + 15;
  1153.     MABlockMove(theCMNUPtr, theMENUPtr, i);        // move menu header into MENU resource 
  1154.     theCMNUPtr = (Ptr)(theCMNUPtr + i);
  1155.     theMENUPtr = (Ptr)(theMENUPtr + i);
  1156.     itemNo = 0;
  1157.     endPtr = (Ptr)(theCMNUPtr + GetHandleSize(CMNUHandle));
  1158.     while ((theCMNUPtr < endPtr) && (((*((CStr255 *)theCMNUPtr)).Length()) != 0))
  1159.     {
  1160.         i = ((*((CStr255 *)theCMNUPtr)).Length()) + 5;
  1161.         MABlockMove(theCMNUPtr, theMENUPtr, i);    // move menu item data sans command number 
  1162.         theCMNUPtr = (Ptr)(theCMNUPtr + i);
  1163.         theMENUPtr = (Ptr)(theMENUPtr + i);
  1164.         if ((((long)theCMNUPtr) & 0x00000001) == 1)// word align 
  1165.             theCMNUPtr = (Ptr)(theCMNUPtr + 1);
  1166.         cmdNo = *((CommandNumberPtr)theCMNUPtr);
  1167.         ++itemNo;
  1168.         theCMNUPtr = (Ptr)(theCMNUPtr + sizeof(CommandNumber));
  1169.  
  1170.         gCmdTable->AddToTable(cmdNo, menuNo, itemNo);
  1171.     }
  1172.  
  1173.     (*theMENUPtr) = 0;                            // termination mark 
  1174.     ++theMENUPtr;
  1175.     Size theMenuSize = (Size)(theMENUPtr - StripLong((*theMenuRef)));
  1176.  
  1177.     HUnlock(CMNUHandle);
  1178.     HUnlock((Handle)theMenuRef);
  1179.  
  1180.     // Set the handle size AFTER unlocking it ;-)
  1181.     SetPermHandleSize((Handle)theMenuRef, theMenuSize);
  1182.  
  1183.     return theMenuRef;
  1184. }
  1185.  
  1186. //----------------------------------------------------------------------------------------
  1187. // InitUMenuMgr: 
  1188. //----------------------------------------------------------------------------------------
  1189. #pragma segment MAInit
  1190.  
  1191. void InitUMenuMgr()
  1192. {
  1193.     short num;
  1194.     MenuRef newMenu;
  1195.     Handle h;
  1196.     short i;
  1197.     ResNumber menuResID;
  1198.     ResType menuResourceType;
  1199.     CStr255 menuResourceName;
  1200.  
  1201.     // Create the MenuResID -> MenuID translation table
  1202.     gMenuIDList = new TMenuIDList;
  1203.     gMenuIDList->IMenuIDList();
  1204.  
  1205.     // Create the command table 
  1206.     gCmdTable = new TCmdTable;
  1207.     gCmdTable->ICmdTable();
  1208.  
  1209.     // Create the menu table 
  1210.     gMenuTable = new TMenuTable;
  1211.     gMenuTable->IMenuTable();
  1212.  
  1213.     // initialize all CMNUs with positive id
  1214.     num = CountResources('CMNU');
  1215.     FailResError();
  1216.     for (i = 1; i <= num; ++i)
  1217.     {
  1218.         Handle aCMNUHandle = GetIndResource('CMNU', i);
  1219.         FailNILResource(aCMNUHandle);
  1220.         HNoPurge(aCMNUHandle);                    // If it was purgeable it might squirt away
  1221.         GetResInfo(aCMNUHandle, &menuResID, &menuResourceType, menuResourceName);
  1222.         short menuID = (*(MenuRef)aCMNUHandle)->menuID;
  1223.         if (((*(MenuRef)aCMNUHandle)->menuID) > 0)// not in reserved range
  1224.         {
  1225.             // load the menudef and store its reference in the menu 
  1226.             newMenu = ConvertToMenu(aCMNUHandle);
  1227.             ReleaseResource(aCMNUHandle);        // won't be needing this since it's we have a MENU now
  1228.             h = GetResource('MDEF', *((short*)(&(*newMenu)->menuProc)));
  1229.             (*newMenu)->menuProc = h;
  1230.             //CalcMenuSize(newMenu);
  1231.             MAInsertInMenuTable(newMenu, menuResID);
  1232.         }
  1233.         else
  1234.             ReleaseResource(aCMNUHandle);        // Goodbye!
  1235.     }
  1236.  
  1237.     // initialize all MENUs with positive id
  1238.     num = CountResources('MENU');
  1239.     FailResError();
  1240.     for (i = 1; i <= num; ++i)
  1241.     {
  1242.         newMenu = (MenuRef)GetIndResource('MENU', i);
  1243.         if (newMenu)
  1244.         {
  1245.             GetResInfo((Handle)newMenu, &menuResID, &menuResourceType, menuResourceName);
  1246.  
  1247.             THz itsZone = HandleZone((Handle)newMenu);
  1248.             // not a System menu and not in reserved range
  1249.             if ((itsZone != SystemZone()) && ((*newMenu)->menuID) > 0)
  1250.             {
  1251.                 // load the menudef and store its reference in the menu 
  1252.                 // h = GetResource('MDEF', (short)(((long)(*newMenu)->menuProc) >> sizeof(short)));
  1253.                 h = GetResource('MDEF', *((short*)(&(*newMenu)->menuProc)));
  1254.                 (*newMenu)->menuProc = h;
  1255.  
  1256.                 MAInsertInMenuTable(newMenu, menuResID);
  1257.             }
  1258.         }
  1259.     }
  1260.  
  1261. #if !qPowerPC
  1262.     // Create the NULL menu proc 
  1263.     pHNullMenuProc = NewPermHandle(sizeof(JmpInstructionTemplate));
  1264.     PatchJmpInstruction(*pHNullMenuProc, (void*)StripLong(NullMenuProc));
  1265. #else
  1266.     // Create a MenuDefUPP for PowerPC builds…
  1267.     pHNullMenuProc = NewPermHandle(sizeof(RoutineDescriptor));
  1268.     RoutineDescriptor aMDEFUPP = BUILD_ROUTINE_DESCRIPTOR(uppMenuDefProcInfo, NullMenuProc);
  1269.     ::BlockMove(&aMDEFUPP, *pHNullMenuProc, sizeof(RoutineDescriptor));// leave as BlockMove so cache flushes
  1270. #endif
  1271.  
  1272. #if qDebugMsg
  1273.     if (cUndo - cEditBase != kSysUndo)
  1274.         fprintf(stderr, "Invalid UNDO command number\n");
  1275.     if (cCut - cEditBase != kSysCut)
  1276.         fprintf(stderr, "Invalid CUT command number\n");
  1277.     if (cCopy - cEditBase != kSysCopy)
  1278.         fprintf(stderr, "Invalid COPY command number\n");
  1279.     if (cPaste - cEditBase != kSysPaste)
  1280.         fprintf(stderr, "Invalid PASTE command number\n");
  1281.     if (cClear - cEditBase != kSysClear)
  1282.         fprintf(stderr, "Invalid CLEAR command number\n");
  1283. #endif
  1284.  
  1285. }
  1286.  
  1287. //----------------------------------------------------------------------------------------
  1288. // IsManagedMenu: 
  1289. //----------------------------------------------------------------------------------------
  1290. #pragma segment MAMenuRes
  1291.  
  1292. Boolean IsManagedMenu(MenuRef theMenu)
  1293. {
  1294.     return gMenuTable->GetIdentityItemNo((Handle)theMenu) != kEmptyIndex;
  1295. }
  1296.  
  1297. //----------------------------------------------------------------------------------------
  1298. // MAGetMenuRef: 
  1299. //----------------------------------------------------------------------------------------
  1300. #pragma segment MAMenuRes
  1301.  
  1302. MenuRef MAGetMenuRef(MenuID menuID)
  1303. {
  1304.     MenuRef theMenu = ::GetMenuHandle(menuID);    // do this first ... the menu is likely to
  1305.     // be in the menubar and more likely of
  1306.     // success, hence, faster
  1307.  
  1308.     if (theMenu == NULL)                        // Try the menu list 
  1309.         theMenu = gMenuTable->GetMenu(menuID);
  1310.  
  1311.     return theMenu;
  1312. }
  1313.  
  1314. //----------------------------------------------------------------------------------------
  1315. // MAGetMenu: 
  1316. //----------------------------------------------------------------------------------------
  1317. #pragma segment MAMenuRes
  1318.  
  1319. MenuRef MAGetMenu(ResNumber menuResID)
  1320. {
  1321.     MenuID menuID = gMenuIDList->MenuIDFromResID(menuResID);
  1322.  
  1323.     MenuRef theMenu = MAGetMenuRef(menuID);        // First see if the menu is resident
  1324.  
  1325.     if (theMenu == NULL)                        // darn! Try the resource chain 
  1326.         theMenu = GetResMenu(menuResID);
  1327.  
  1328.     return theMenu;
  1329. }
  1330.  
  1331. //----------------------------------------------------------------------------------------
  1332. // MAGetNewMBar: 
  1333. //----------------------------------------------------------------------------------------
  1334. #pragma segment MAInit
  1335.  
  1336. Handle MAGetNewMBar(ResNumber menuRsrcID)
  1337. {
  1338.     MCTableHandle theColorTab;
  1339.     Handle itsRsrcHandle;
  1340.     SignedByte savedState;
  1341.     Handle itsNewMBar;
  1342.  
  1343.     if (qNeedsColorQD || HasColorQD())
  1344.         theColorTab = GetMCInfo();
  1345.  
  1346.     // make the 'MBAR' resource non-purgeable, so the Toolbox doesn't die 
  1347.     itsRsrcHandle = GetResource('MBAR', menuRsrcID);
  1348.     if (itsRsrcHandle)
  1349.     {
  1350.         savedState = HGetState(itsRsrcHandle);
  1351.         HNoPurge(itsRsrcHandle);
  1352.     }
  1353.  
  1354.     itsNewMBar = GetNewMBar(menuRsrcID);
  1355.  
  1356.     // restore the 'MBAR' resource 
  1357.     if (itsRsrcHandle)
  1358.         HSetState(itsRsrcHandle, savedState);
  1359.  
  1360.     if (theColorTab && (qNeedsColorQD || HasColorQD()))
  1361.     {
  1362.         HLock((Handle)theColorTab);
  1363.         SetMCEntries((short)(GetHandleSize((Handle)theColorTab) / sizeof(MCEntry)), (*theColorTab));
  1364.         HUnlock((Handle)theColorTab);
  1365.         DisposeMCInfo(theColorTab);
  1366.     }
  1367.  
  1368.     return itsNewMBar;
  1369. }
  1370.  
  1371. //----------------------------------------------------------------------------------------
  1372. // MAInsertInMenuTable: 
  1373. //----------------------------------------------------------------------------------------
  1374. #pragma segment MAMenuRes
  1375.  
  1376. void MAInsertInMenuTable(MenuRef theMenu,
  1377.                          ResNumber menuResID)
  1378. {
  1379.     gMenuTable->Insert((Handle)theMenu);
  1380.  
  1381.     // Add the menu to the translation table
  1382.     gMenuIDList->AddToTable(menuResID, (*theMenu)->menuID);
  1383. }
  1384.  
  1385. //----------------------------------------------------------------------------------------
  1386. // MAInsertMenu: 
  1387. //----------------------------------------------------------------------------------------
  1388. #pragma segment MAMenuRes
  1389.  
  1390. void MAInsertMenu(MenuRef theMenu,
  1391.                   ResNumber menuResID,
  1392.                   MenuID beforeID)
  1393. {
  1394.     MenuCRsrcHandle theColorRsrc;
  1395.  
  1396.     InsertMenu(theMenu, beforeID);
  1397.  
  1398.     // Since only GetMenu automatically loads the appropriate color information,
  1399.     // and (sigh) since we can only call GetMenu once, and if you call DeleteMenu
  1400.     // all the good color stuff goes away (double sigh) we'll have to help out
  1401.     // the Menu Manager by doing its job for it
  1402.  
  1403.     if (qNeedsColorQD || HasColorQD())
  1404.     {
  1405.         // n.b. This is using the menuID of the menu as a resource ID, which is incorrect
  1406.         theColorRsrc = (MenuCRsrcHandle)GetResource('mctb', menuResID);
  1407.         if (theColorRsrc)
  1408.         {
  1409.             HLock((Handle)theColorRsrc);
  1410.             SetMCEntries((*theColorRsrc)->numEntries, &((*theColorRsrc)->mcEntryRecs[0]));
  1411.             HUnlock((Handle)theColorRsrc);
  1412.             ReleaseResource((Handle)theColorRsrc);
  1413.         }
  1414.     }
  1415. }
  1416.  
  1417. //----------------------------------------------------------------------------------------
  1418. // NeedCalcMenuSize: 
  1419. //----------------------------------------------------------------------------------------
  1420. #pragma segment MAMenuRes
  1421.  
  1422. void NeedCalcMenuSize(MenuRef aMenuRef)
  1423. {
  1424.     if ((*aMenuRef)->menuProc == pHNullMenuProc)
  1425.         (*aMenuRef)->menuWidth = 0;
  1426. }
  1427.  
  1428. //----------------------------------------------------------------------------------------
  1429. // NullMenuProc: a NULL menuProc that is used to inhibit re-calculating the menu's size
  1430. // after each call to EnableItem, CheckItem, etc.
  1431. //----------------------------------------------------------------------------------------
  1432. #pragma segment MAMenuRes
  1433.  
  1434. pascal void NullMenuProc(short,
  1435.                          MenuRef aMenuRef,
  1436.                          CRect& ,
  1437.                          CPoint,
  1438.                          short&)
  1439. {
  1440.     (*aMenuRef)->menuWidth = 0;
  1441. }
  1442.  
  1443. //----------------------------------------------------------------------------------------
  1444. // If hierarchical the range of IDs for applications is restricted.  See IM V-236.
  1445. const ResNumber kHierarchicalMin = 0;
  1446. const ResNumber kHierarchicalMax = 235;
  1447.  
  1448. //----------------------------------------------------------------------------------------
  1449. // IsSetupMenu: 
  1450. //----------------------------------------------------------------------------------------
  1451. #pragma segment MAMenuRes
  1452.  
  1453. Boolean IsSetupMenu(MenuRef aMenuRef,
  1454.                     Boolean isHierarchical)
  1455. {
  1456. #if qDebug
  1457.     if (!IsHandle((Handle)aMenuRef))
  1458.     {
  1459.         VerboseIsHandle((Handle)aMenuRef);
  1460.         ProgramBreak("In IsSetupMenu: not handed a handle.");
  1461.         return FALSE;
  1462.     }
  1463. #endif
  1464.  
  1465.     MenuID menuID = (*aMenuRef)->menuID;
  1466.  
  1467.     if (menuID == mApple)
  1468.         return FALSE;                            // _NEVER_ managed! 
  1469.  
  1470. #if qDebug
  1471.     if (menuID == mDebug)
  1472.         return TRUE;
  1473. #endif
  1474.  
  1475.     if (isHierarchical)
  1476.     {
  1477.         if ((menuID < kHierarchicalMin) || (menuID > kHierarchicalMax))
  1478.             return FALSE;                        // must be in valid range for hierarchicals
  1479.     }
  1480.     return ((menuID >= mFirstMenu) && (menuID <= mLastMenu));// Range of managed menus
  1481.  
  1482. }
  1483.  
  1484. //----------------------------------------------------------------------------------------
  1485. // CSetupMenus:
  1486. //----------------------------------------------------------------------------------------
  1487.  
  1488. const short kMaxSetupMenus = mLastMenu + 1;
  1489.  
  1490. class CSetupMenus
  1491. {
  1492. public:
  1493.     inline CSetupMenus() :
  1494.     fCount(0)
  1495.     { }
  1496.  
  1497.     void StartMenuSetup(MenuRef aMenuRef);
  1498.     void EndMenuSetup();
  1499.  
  1500. protected:
  1501.     short fCount;
  1502.     MenuRef fMenuRef[kMaxSetupMenus];
  1503.     Boolean fEnabled[kMaxSetupMenus];
  1504.     Handle fMenuProc[kMaxSetupMenus];
  1505. };
  1506.  
  1507. //----------------------------------------------------------------------------------------
  1508. // CSetupMenus::StartMenuSetup: 
  1509. //----------------------------------------------------------------------------------------
  1510. #pragma segment MAMenuRes
  1511.  
  1512. void CSetupMenus::StartMenuSetup(MenuRef aMenuRef)
  1513. {
  1514. #if qDebug
  1515.     if (fCount >= kMaxSetupMenus)
  1516.     {
  1517.         ProgramBreak("Array overflow: too many setup menus.");
  1518.         return;
  1519.     }
  1520. #endif
  1521.  
  1522.     // Remember if the menu itself was enabled. 
  1523.     // Save the menu's menuproc
  1524.     fMenuRef[fCount] = aMenuRef;
  1525.     fEnabled[fCount] = (Boolean)((*aMenuRef)->enableFlags & 1);
  1526.     fMenuProc[fCount] = (*aMenuRef)->menuProc;    // See comment below 
  1527.     ++fCount;
  1528.  
  1529.     // Set the menu's menuproc to the NullMenuProc, so that
  1530.     // CalcMenuSize is disabled (will do ÇalcMenuSize at end of setup).
  1531.     (*aMenuRef)->menuProc = pHNullMenuProc;
  1532.  
  1533.     // Disable the menu and all of its items. 
  1534.     (*aMenuRef)->enableFlags = 0;
  1535.  
  1536.     // Uncheck all items.
  1537.     short nItems = CountMItems(aMenuRef);
  1538.     for (short item = 1; item <= nItems; ++item)// Make sure we don't check items with sub-menus 
  1539.     {
  1540.         short theCmd;
  1541.         GetItemCmd(aMenuRef, item, &theCmd);
  1542.         if (theCmd != hMenuCmd)
  1543.             CheckItem(aMenuRef, item, FALSE);    // moves/purges memory 
  1544.     }
  1545. }
  1546.  
  1547. //----------------------------------------------------------------------------------------
  1548. // CSetupMenus::EndMenuSetup: 
  1549. //----------------------------------------------------------------------------------------
  1550.  
  1551. void CSetupMenus::EndMenuSetup()
  1552. {
  1553.     for (short i = 0; i < fCount; ++i)
  1554.     {
  1555.         MenuRef aMenuRef = fMenuRef[i];
  1556.  
  1557.         long newFlags = (*aMenuRef)->enableFlags;
  1558.         // If any items are enabled, enable the menu 
  1559.         if (newFlags != 0)
  1560.         {
  1561.             newFlags = (1 | newFlags);
  1562.             (*aMenuRef)->enableFlags = newFlags;
  1563.         }
  1564.  
  1565.         // If the menu's enabled state changed, we have to draw the menu bar. 
  1566.         MenuID menuID = (*aMenuRef)->menuID;
  1567.         if (((newFlags & 1) == 1) != fEnabled[i])
  1568.             InvalidateMenuBar();
  1569.  
  1570.         // Restore the menuproc. 
  1571.         (*aMenuRef)->menuProc = fMenuProc[i];
  1572.  
  1573.         // menuWidth set to 0 by routines that require CalcMenuSize, by
  1574.         // calling NeedCalcMenu.
  1575.         if (!(*aMenuRef)->menuWidth)
  1576.             CalcMenuSize(aMenuRef);
  1577.     }
  1578. }
  1579.  
  1580. //----------------------------------------------------------------------------------------
  1581. // PerformMenuSetup: 
  1582. //----------------------------------------------------------------------------------------
  1583.  
  1584. void PerformMenuSetup(MenuSetupType TheMenuSetterUpper,
  1585.                       void* yourDataPtr)
  1586. {
  1587.     CSetupMenus setup;
  1588.  
  1589.     {                                            // in a block to destroy the iterator
  1590.         CMenuIterator iter;
  1591.         for (MenuRef item = iter.FirstMenu(); iter.More(); item = (MenuRef)iter.NextMenu())
  1592.             if (IsSetupMenu(item, kHierarchical))
  1593.                 setup.StartMenuSetup(item);
  1594.     }
  1595.  
  1596.     TheMenuSetterUpper(yourDataPtr);
  1597.  
  1598.     setup.EndMenuSetup();
  1599.  
  1600.     ValidateMenus();
  1601. }
  1602.  
  1603. //----------------------------------------------------------------------------------------
  1604. // SetCommandIcon: 
  1605. //----------------------------------------------------------------------------------------
  1606. #pragma segment MAMenuRes
  1607.  
  1608. void SetCommandIcon(CommandNumber aCommand,
  1609.                     Byte menuIcon)
  1610. {
  1611. #if qDebugMsg
  1612.     if (gTraceSetupMenus)
  1613.         fprintf(stderr, "..... SetCommandIcon(%c%d)\n", TraceMenuName(aCommand), menuIcon);
  1614. #endif
  1615.  
  1616.     MenuID menuID;
  1617.     short item;
  1618.  
  1619.     MenuRef aMenuRef = CommandToComponents(aCommand, menuID, item);
  1620.     if (aMenuRef)
  1621.         SetItemIcon(aMenuRef, item, menuIcon);
  1622. }
  1623.  
  1624. //----------------------------------------------------------------------------------------
  1625. // SetCommandName: 
  1626. //----------------------------------------------------------------------------------------
  1627. #pragma segment MAMenuRes
  1628.  
  1629. void SetCommandName(CommandNumber aCommand,
  1630.                     const CStr255& menuText)
  1631. {
  1632. #if qDebugMsg
  1633.     if (gTraceSetupMenus)
  1634.         fprintf(stderr, "..... SetCommandName(%c'%s')\n", TraceMenuName(aCommand), menuText);
  1635. #endif
  1636.  
  1637. #if qDebug
  1638.     if (menuText.IsEmpty())
  1639.         ProgramBreak("SetCommandName: empty menuText - may corrupt the menu handle!");
  1640. #endif
  1641.  
  1642.     MenuID menuID;
  1643.     short item;
  1644.  
  1645.     MenuRef aMenuRef = CommandToComponents(aCommand, menuID, item);
  1646.     if (aMenuRef)
  1647.         SetMenuItemText(aMenuRef, item, menuText);
  1648. }
  1649.  
  1650. //----------------------------------------------------------------------------------------
  1651. // SetIndividualCommandName: 
  1652. //----------------------------------------------------------------------------------------
  1653. #pragma segment MAMenuRes
  1654.  
  1655. void SetIndividualCommandName(CommandNumber aCommand,
  1656.                               ResNumber rsrcID,
  1657.                               short strIndex)
  1658. {
  1659.     CStr255 s;
  1660.  
  1661.     GetIndString(s, rsrcID, strIndex);
  1662.     SetCommandName(aCommand, s);
  1663. }
  1664.  
  1665. //----------------------------------------------------------------------------------------
  1666. // SetMenuState: 
  1667. //----------------------------------------------------------------------------------------
  1668. #pragma segment MAMenuRes
  1669.  
  1670. void SetMenuState(CommandNumber aCommand,
  1671.                   ResNumber rsrcID,
  1672.                   short falseBuzzItem,
  1673.                   short trueBuzzItem,
  1674.                   Boolean stateVariable)
  1675. {
  1676.     SetIndividualCommandName(aCommand, rsrcID, stateVariable ? trueBuzzItem : falseBuzzItem);
  1677. }
  1678.  
  1679. //----------------------------------------------------------------------------------------
  1680. // SetStyle: 
  1681. //----------------------------------------------------------------------------------------
  1682. #pragma segment MAMenuRes
  1683.  
  1684. void SetStyle(CommandNumber aCommand,
  1685.               /* Style */
  1686.               short aStyle)
  1687. {
  1688. #if qDebugMsg
  1689.     if (gTraceSetupMenus)
  1690.         fprintf(stderr, "..... SetStyle(%c%d)\n", TraceMenuName(aCommand), *((Ptr) & aStyle));
  1691. #endif
  1692.  
  1693.     MenuID menuID;
  1694.     short item;
  1695.  
  1696.     MenuRef aMenuRef = CommandToComponents(aCommand, menuID, item);
  1697.     if (aMenuRef)
  1698.         SetItemStyle(aMenuRef, item, aStyle);
  1699. }
  1700.  
  1701.  
  1702. //----------------------------------------------------------------------------------------
  1703. // MAHiliteMenu: 
  1704. //----------------------------------------------------------------------------------------
  1705. #pragma segment MAMenuRes
  1706.  
  1707. void MAHiliteMenu(short menuID)
  1708. {
  1709.     if (menuID || ::LMGetTheMenu())
  1710.         ::HiliteMenu(menuID);
  1711. }
  1712.  
  1713. #if qContainer
  1714.  
  1715. //----------------------------------------------------------------------------------------
  1716. // MARegisterMenu
  1717. //----------------------------------------------------------------------------------------
  1718. #pragma segment MAInit
  1719.  
  1720. void MARegisterMenu(CACommandID id,
  1721.                     CommandNumber number)
  1722. {
  1723.     MenuID menu;
  1724.     short item;
  1725.     CommandToMenuItem(number, menu, item);
  1726.     if (menu > 0)
  1727.         CARegisterCommand(id, menu, 0);
  1728. }
  1729.  
  1730. //----------------------------------------------------------------------------------------
  1731. // MARegisterCommand
  1732. //----------------------------------------------------------------------------------------
  1733. #pragma segment MAInit
  1734.  
  1735. void MARegisterCommand(CACommandID id,
  1736.                        CommandNumber number)
  1737. {
  1738.     MenuID menu;
  1739.     short item;
  1740.     CommandToMenuItem(number, menu, item);
  1741.     if ((menu > 0) && (item > 0))
  1742.         CARegisterCommand(id, menu, item);
  1743. }
  1744.  
  1745. //----------------------------------------------------------------------------------------
  1746. // MA_CAInitMenus
  1747. //----------------------------------------------------------------------------------------
  1748. #pragma segment MAInit
  1749.  
  1750. void MA_CASetSharedMenuBar()
  1751. {
  1752.     if (gContainerLib)
  1753.     {
  1754.         /*
  1755.  
  1756.           AS OF 12/08/95:
  1757.           This requires a modified version of CALib (which has not been reviewed by Tantek)
  1758.           to run.
  1759.  
  1760.         */
  1761.  
  1762.         MenuHandle theAppleMenu = gMenuTable->GetMenu(mApple);
  1763.         MenuHandle theFileMenu = gMenuTable->GetMenu(mDocument);
  1764.         MenuHandle theEditMenu = gMenuTable->GetMenu(mOpenDocEdit);
  1765.  
  1766.         if (theAppleMenu && theFileMenu && theEditMenu)
  1767.         {
  1768.             //••••not using MAInsertMenu b/c that requires menuResID's
  1769.             ::InsertMenu(theAppleMenu, 1);
  1770.             ::InsertMenu(theFileMenu, 2);
  1771.             ::InsertMenu(theEditMenu, 3);
  1772.         }
  1773. #if qDebug
  1774.         else
  1775.         {
  1776.             // P.S. Your Hosed....
  1777.             DebugStr("\pMacApp could not retrieve the menu handles from the menu table.");
  1778.         }
  1779. #endif
  1780.  
  1781.         CASetBaseMenuBar(GetMenuBar());
  1782.         FailOSErr(CAError());
  1783.     }
  1784. }
  1785.  
  1786. //----------------------------------------------------------------------------------------
  1787. // MA_CARegisterSharedMenuCommands
  1788. //----------------------------------------------------------------------------------------
  1789. #pragma segment MAInit
  1790.  
  1791. void MA_CARegisterSharedMenuCommands()
  1792. {
  1793.  
  1794.     //  The CA must register a minimum set of menu from the apple, file, edit menus.
  1795.     //  Apple - About
  1796.     //    File - kODCommandInsert
  1797.     //    Edit - Undo, Redo, Cut, Copy, Paste, PasteAs, Clear, SelectAll
  1798.  
  1799.     MARegisterMenu(kODCommandAppleMenu, cAboutApp);
  1800.     MARegisterCommand(kODCommandAbout, cAboutApp);
  1801.  
  1802.     MARegisterMenu(kODCommandDocumentMenu, cNew);
  1803.     MARegisterCommand(kODCommandNew, cNew);
  1804.     MARegisterCommand(kODCommandOpenDocument, kODCommandOpenDocument);
  1805.     MARegisterCommand(kODCommandOpen, cOpen);
  1806.     MARegisterCommand(kODCommandInsert, kODCommandInsert);
  1807.     MARegisterCommand(kODCommandClose, cClose);
  1808.     MARegisterCommand(kODCommandSave, cSave);
  1809.     MARegisterCommand(kODCommandSaveACopy, cSaveCopy);
  1810.     MARegisterCommand(kODCommandRevert, cRevert);
  1811.     MARegisterCommand(kODCommandDraft, kODCommandDraft);
  1812.     MARegisterCommand(kODCommandDocumentInfo, kODCommandDocumentInfo);
  1813.     MARegisterCommand(kODCommandPageSetup, cPageSetup);
  1814.     MARegisterCommand(kODCommandPrint, cPrint);
  1815.  
  1816.     MARegisterMenu(kODCommandEditMenu, cUndo);
  1817.     MARegisterCommand(kODCommandUndo, cUndo);
  1818.     MARegisterCommand(kODCommandRedo, kODCommandRedo);
  1819.     MARegisterCommand(kODCommandCut, cCut);
  1820.     MARegisterCommand(kODCommandCopy, cCopy);
  1821.     MARegisterCommand(kODCommandPaste, cPaste);
  1822.     MARegisterCommand(kODCommandPasteAs, kODCommandPasteAs);
  1823.     MARegisterCommand(kODCommandClear, cClear);
  1824.     MARegisterCommand(kODCommandSelectAll, cSelectAll);
  1825.     MARegisterCommand(kODCommandGetPartInfo, kODCommandGetPartInfo);
  1826.     MARegisterCommand(kODCommandPreferences, kODCommandPreferences);
  1827.     MARegisterCommand(kODCommandViewAsWin, kODCommandViewAsWin);
  1828.  
  1829.     //••• If the user decided to change Apple,File, or Edit structre, they will
  1830.     //need to override this method
  1831. }
  1832. #endif
  1833.  
  1834. //========================================================================================
  1835. // CLASS CMenuIterator
  1836. //========================================================================================
  1837. #undef Inherited
  1838. #define Inherited CHandleIterator
  1839.  
  1840. //----------------------------------------------------------------------------------------
  1841. // CMenuIterator::CMenuIterator: A simple iterator for menus.
  1842. //----------------------------------------------------------------------------------------
  1843. #pragma segment MAMenuRes
  1844.  
  1845. CMenuIterator::CMenuIterator() :
  1846.     CHandleIterator(gMenuTable, kIterateForward)
  1847. {
  1848. }
  1849.  
  1850. //----------------------------------------------------------------------------------------
  1851. // CMenuIterator::~CMenuIterator: 
  1852. //----------------------------------------------------------------------------------------
  1853. #pragma segment IteratorRes
  1854.  
  1855. CMenuIterator::~CMenuIterator()
  1856. {
  1857. }
  1858.  
  1859. //----------------------------------------------------------------------------------------
  1860. // CMenuIterator::Advance: 
  1861. //----------------------------------------------------------------------------------------
  1862. #pragma segment MAMenuRes
  1863.  
  1864. void CMenuIterator::Advance()                    // override
  1865. {
  1866.     CHandleIterator::Advance();
  1867.  
  1868.     // only point at menus that are in the menulist
  1869.     if (More() && !::GetMenuHandle((*(CurrentMenu()))->menuID))
  1870.         Advance();
  1871. }
  1872.  
  1873.  
  1874. //========================================================================================
  1875. // CLASS TMenuBarManager
  1876. //========================================================================================
  1877. #undef Inherited
  1878. #define Inherited TObject
  1879.  
  1880. #pragma segment MAInit
  1881. MA_DEFINE_CLASS_M1(TMenuBarManager,
  1882.                    Inherited);
  1883.  
  1884. //----------------------------------------------------------------------------------------
  1885. // TMenuBarManager destructor
  1886. //----------------------------------------------------------------------------------------
  1887. #pragma segment MADestructorRes
  1888.  
  1889. TMenuBarManager::~TMenuBarManager()
  1890. {
  1891. }
  1892.  
  1893. //----------------------------------------------------------------------------------------
  1894. // TMenuBarManager::IMenuBarManager: 
  1895. //----------------------------------------------------------------------------------------
  1896. #pragma segment MAMenuRes
  1897. void TMenuBarManager::IMenuBarManager(ResNumber otherMenus)
  1898. {
  1899.     const CStr255 kParamText1 = "^0";
  1900.  
  1901.     IObject();
  1902.  
  1903.     fDisplayedMenus = kNoResource;
  1904.     fPreferredMenuBarID = kNoResource;
  1905.     fDisplayedHierMenus = kNoResource;
  1906.     fPreferredHierMenuBarID = kNoResource;
  1907. #if qContainer
  1908.     fAppMenuBar = NULL;
  1909. #endif
  1910.  
  1911.  
  1912.     // Add in the "other" menus, then clear them from the MenuBar
  1913.     AddMenuBar(otherMenus, kNotHierarchical);
  1914.     ClearMenuBar();
  1915.  
  1916.     // Initialize the Apple menu 
  1917.     MenuRef aMenu = MAGetMenu(mApple);
  1918.     if (aMenu)
  1919.         AppendResMenu(aMenu, 'DRVR');
  1920.  
  1921.     // If the "About" item contains the paramtext keystring (^0) then substitute the
  1922.     // Application's name
  1923.     CStr255 s;
  1924.     CommandToName(cAboutApp, s);
  1925.     short i = s.Pos(kParamText1);
  1926.     if (i)
  1927.     {
  1928.         CStr255 apName;
  1929.  
  1930.         gDispatcher->GetApplicationName(apName);
  1931.         s.Delete(i, kParamText1.Length());
  1932.         s.Insert(apName, i);
  1933.         SetCommandName(cAboutApp, s);
  1934.     }
  1935.  
  1936. #if qContainer
  1937.     if (gContainerLib)
  1938.     {
  1939.         MA_CASetSharedMenuBar();
  1940.         MA_CARegisterSharedMenuCommands();
  1941.     }
  1942. #endif        
  1943.  
  1944. }
  1945.  
  1946. //----------------------------------------------------------------------------------------
  1947. // TMenuBarManager::SetPreferredMenuBarID: 
  1948. //----------------------------------------------------------------------------------------
  1949. #pragma segment MAMenuRes
  1950. void TMenuBarManager::SetPreferredMenuBarID(ResNumber theID)
  1951. {
  1952.     fPreferredMenuBarID = theID;
  1953. }
  1954.  
  1955. //----------------------------------------------------------------------------------------
  1956. // TMenuBarManager::GetPreferredMenuBarID: 
  1957. //----------------------------------------------------------------------------------------
  1958. #pragma segment MAMenuRes
  1959. ResNumber TMenuBarManager::GetPreferredMenuBarID()
  1960. {
  1961.     return fPreferredMenuBarID;
  1962. }
  1963.  
  1964. //----------------------------------------------------------------------------------------
  1965. // TMenuBarManager::SetPreferredHierMenuBarID: 
  1966. //----------------------------------------------------------------------------------------
  1967. #pragma segment MAMenuRes
  1968. void TMenuBarManager::SetPreferredHierMenuBarID(ResNumber theID)
  1969. {
  1970.     fPreferredHierMenuBarID = theID;
  1971. }
  1972.  
  1973. //----------------------------------------------------------------------------------------
  1974. // TMenuBarManager::GetPreferredHierMenuBarID: 
  1975. //----------------------------------------------------------------------------------------
  1976. #pragma segment MAMenuRes
  1977. ResNumber TMenuBarManager::GetPreferredHierMenuBarID()
  1978. {
  1979.     return fPreferredHierMenuBarID;
  1980. }
  1981.  
  1982. //----------------------------------------------------------------------------------------
  1983. // TMenuBarManager::InstallPreferredMenus: 
  1984. //----------------------------------------------------------------------------------------
  1985. #pragma segment MAMenuRes
  1986. void TMenuBarManager::InstallPreferredMenus()
  1987. {
  1988.     if (((fDisplayedMenus != fPreferredMenuBarID) && (fPreferredMenuBarID != kNoResource)) || ((fDisplayedHierMenus != fPreferredHierMenuBarID) && (fPreferredHierMenuBarID != kNoResource)))
  1989.     {
  1990.         ClearMenuBar();
  1991.  
  1992.         if (fPreferredMenuBarID != kNoResource)
  1993.         {
  1994.             AddMenuBar(fPreferredMenuBarID, kNotHierarchical);
  1995.             fDisplayedMenus = fPreferredMenuBarID;
  1996.         }
  1997.         else
  1998.             AddMenuBar(fDisplayedMenus, kNotHierarchical);
  1999.  
  2000.         if (fPreferredHierMenuBarID != kNoResource)
  2001.         {
  2002.             AddMenuBar(fPreferredHierMenuBarID, kHierarchical);
  2003.             fDisplayedHierMenus = fPreferredHierMenuBarID;
  2004.         }
  2005.         else
  2006.             AddMenuBar(fDisplayedHierMenus, kHierarchical);
  2007.  
  2008.         // We must reinsert the help menus whenever ClearMenuBar is called
  2009.         gDispatcher->InstallHelpMenuItems();
  2010.  
  2011. #if qContainer
  2012.         fAppMenuBar = GetMenuBar();
  2013. #endif
  2014.  
  2015.     }
  2016. }
  2017.  
  2018. //----------------------------------------------------------------------------------------
  2019. // TMenuBarManager::Reset: 
  2020. //----------------------------------------------------------------------------------------
  2021. #pragma segment MAMenuRes
  2022. void TMenuBarManager::Reset()
  2023. {
  2024.     fPreferredMenuBarID = kNoResource;
  2025.     fPreferredHierMenuBarID = kNoResource;
  2026. }
  2027.  
  2028. //----------------------------------------------------------------------------------------
  2029. // TMenuBarManager::AddHelpMenuItem: 
  2030. //----------------------------------------------------------------------------------------
  2031. #pragma segment MAMenuRes
  2032.  
  2033. void TMenuBarManager::AddHelpMenuItem(CStr255 helpText,
  2034.                                       CommandNumber helpCommand)
  2035. {
  2036.     MenuRef helpMenu = NULL;
  2037.     short newHelpItemNo = 9999;
  2038.     const CStr255 kParamText1 = "^0";
  2039.     OSErr err = noErr;
  2040.  
  2041.     // If the help item contains the paramtext keystring (^0) then substitute the
  2042.     // Application's name
  2043.     short i = helpText.Pos(kParamText1);
  2044.     if (i)
  2045.     {
  2046.         CStr255 apName;
  2047.  
  2048.         gDispatcher->GetApplicationName(apName);
  2049.         helpText.Delete(i, kParamText1.Length());
  2050.         helpText.Insert(apName, i);
  2051.     }
  2052.  
  2053.     // Put the help item at the end of the help menu
  2054.     err = HMGetHelpMenuHandle(&helpMenu);
  2055.  
  2056.     // If we have a reference to a menu, insert the help command
  2057.     if ((err == noErr) && (helpMenu != NULL))
  2058.     {
  2059.         short oldMenu;
  2060.         short oldItem;
  2061.  
  2062.         // If the new help item is to be inserted at the end of
  2063.         // the list, make sure that its number is correct
  2064.         short nHelpItems = CountMItems(helpMenu);
  2065.         if (newHelpItemNo > nHelpItems)
  2066.             newHelpItemNo = nHelpItems + 1;
  2067.  
  2068.         // Insert the menu, then change its name.  This avoids problems
  2069.         // that might occur if the application name included metacharacters
  2070.         CStr255 helpStr = "Help";
  2071.         InsertMenuItem(helpMenu, helpStr, newHelpItemNo - 1);
  2072.         SetMenuItemText(helpMenu, newHelpItemNo, helpText);
  2073.  
  2074.         // Add the help command number to the command table, but only if it's not already there
  2075.         if (CommandToComponents(helpCommand, oldMenu, oldItem) == NULL)
  2076.             gCmdTable->AddToTable(helpCommand, (*helpMenu)->menuID, newHelpItemNo);
  2077.     }
  2078. }
  2079.  
  2080. //----------------------------------------------------------------------------------------
  2081. // TMenuBarManager::AddMenuItem:
  2082. //----------------------------------------------------------------------------------------
  2083. #pragma segment MAMenuRes
  2084.  
  2085. void TMenuBarManager::AddMenuItem(const CStr255& theMenuItemText,
  2086.                                   MenuID menuNumber,
  2087.                                   short insertAfterItem,
  2088.                                   CommandNumber theMenuItemCommandNumber)
  2089. {
  2090.     short theMenuItem = insertAfterItem;
  2091.     MenuRef theMenuRef = MAGetMenuRef(menuNumber);
  2092.  
  2093.     // If we have a reference to a menu, insert the new menu item
  2094.     if ((theMenuRef != NULL) && (theMenuItemText.Length() > 0))
  2095.     {
  2096.         short oldMenu;
  2097.         short oldItem;
  2098.         short curNumItems;
  2099.  
  2100.         // Figure out where to insert the new menu item
  2101.         curNumItems = CountMItems(theMenuRef);
  2102.         if (theMenuItem > curNumItems)
  2103.             theMenuItem = curNumItems + 1;
  2104.         else
  2105.             // The user passed in where to insert it after so add one to take this into account
  2106.             theMenuItem++;
  2107.  
  2108.         // Insert the menu, then change its name.  This avoids problems
  2109.         // that might occur if the application name included metacharacters
  2110.         // One is subtracted here to take into account insert after item that InsMenuItem does
  2111.         ::InsertMenuItem(theMenuRef, (ConstStr255Param)"\ptemp", theMenuItem - 1);
  2112.         ::SetMenuItemText(theMenuRef, theMenuItem, theMenuItemText);
  2113.  
  2114.         // Add the help command number to the command table, but only if it's not already there
  2115.         if (CommandToComponents(theMenuItemCommandNumber, oldMenu, oldItem) == NULL)
  2116.             gCmdTable->AddNewCmdToTableAndUpdateTable(theMenuItemCommandNumber, (*theMenuRef)->menuID, theMenuItem);
  2117.  
  2118.         // Make sure the menu is updated
  2119.         NeedCalcMenuSize(theMenuRef);
  2120.     }
  2121. }
  2122.  
  2123. //----------------------------------------------------------------------------------------
  2124. // TMenuBarManager::DeleteMenuItem:
  2125. //----------------------------------------------------------------------------------------
  2126. #pragma segment MAMenuRes
  2127.  
  2128. void TMenuBarManager::DeleteMenuItem(CommandNumber theMenuItemCommandNumber)
  2129. {
  2130.     short theMenuNumber;
  2131.     short theItemNumber;
  2132.  
  2133.     gCmdTable->CommandToMenuItem(theMenuItemCommandNumber, theMenuNumber, theItemNumber);
  2134.     if (theMenuNumber)
  2135.     {
  2136.         MenuRef theMenu = MAGetMenuRef(theMenuNumber);
  2137.  
  2138.         // Delete the menu item from the menu
  2139.         if (theMenu != NULL)
  2140.         {
  2141.             ::DeleteMenuItem(theMenu, theItemNumber);
  2142.  
  2143.             // Make sure the menu is updated
  2144.             NeedCalcMenuSize(theMenu);
  2145.         }
  2146.  
  2147.         // Delete the command number from the table
  2148.         gCmdTable->DeleteCmdAndUpdateTable(theMenuItemCommandNumber);
  2149.     }
  2150. }
  2151.  
  2152. //----------------------------------------------------------------------------------------
  2153. // UMenuMgr.cp 
  2154.  
  2155. #pragma segment Inline
  2156.  
  2157.